#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

//int main()
//{
//	int a = -10;
//	//-10是存放在a中，a是整型变量，是4个字节，1个字节是8个比特位，所以4个字节是32个比特位
//	//负数的原反补码各不相同
//	//10000000000000000000000000001010 - 原码
//	//11111111111111111111111111110101 - 反码（负数的反码是符号位不变，其它位取反）
//	//11111111111111111111111111110110 - 补码
//
//
//	int b = 10;
//	//10是存放在b中，b是整型变量，是4个字节，1个字节是8个比特位，所以4个字节是32个比特位
//	//整数的原反补码都相同
//	//00000000000000000000000000001010  -原码
//	//00000000000000000000000000001010  -反码
//	//00000000000000000000000000001010  -补码
//	return 0;
//}


/**********************************************************************************
对于整形来说，数据存放内存中，存放的其实是补码
在计算机系统中，数值一律用补码来表示和储存，原因在于，是用补码，可以将符号位和数值域
统一处理，同时，加法和减法也可以统一处理（CPU只有加法）
此外，原码和补码相互转换，其运算过程是相同的

例如
1 - 1
1 + （-1）
用反码计算 
00000000000000000000000000000001 -  1的反码
11111111111111111111111111111111 - -1的反码
相加得
00000000000000000000000000000000 

用原码计算
00000000000000000000000000000001 -   1的原码
10000000000000000000000000000001 -  -1的原码
相加
10000000000000000000000000000010  - 结果是-2不符合预期
*********************************************************************************/

/****************************************************
//移位操作符
// 移位操作符的操作数只能是整数，且移动的是二进制位
// 1.<<左移操作符 ---- 左边抛弃，右边补零
*******************************************************/



//int main()
//{
//	int a = 6;
//	int b = (a << 1);
//
//	//00000000000000000000000000000110 -原码
//	//00000000000000000000000000000110 -反码
//	//00000000000000000000000000000110 -补码
//	//<<左边抛弃，右边补0
//	//00000000000000000000000000001100 -补码
//	//00000000000000000000000000001100 -原码 -12
//	
//
//	printf("%d\n", a);        //6
//	printf("%d\n", b);        //12
//	
//	return 0;
//}

//int main()
//{
//	int a = -6;
//	//10000000000000000000000000000110 - 原码
//	//11111111111111111111111111111001 - 反码
//	//11111111111111111111111111111010 - 反码
//
//
//	int b = (a << 1);
//	//11111111111111111111111111110100 - b得到的反码
//	//取反+1得到原码(注意，取反的时候符号位不变)
//	//10000000000000000000000000001100 - b的原码
//	//b = 12
//
//	//补充，b是a<<的结果，但a的值不变
//	return 0;
//}

/*******************************************************
//2.右操作符
//第一种：逻辑右移，左边用0填充，右边丢弃
//第二种：算数右移，左边用原该值的符号位填充，右边丢弃
//右移是那种取决于编译器的具体实现，一般是算数右移
***********************************************************/

//int main()
//{
//	int a = 10;
//	int b = (a >> 1);
//	
//	printf("%d\n", a);
//	printf("%d\n", b);
//	//00000000000000000000000000001010 -原反补码
//	//00000000000000000000000000000101 - 右移一位之后的原反补码
//	return 0;
//}

/***********************************************************************
补充：
1.不要移动负数位，这个是标准未定的行为
2.操作数是整数，不要胡来
3.左移一般情况下可以实现乘2的效果
4.右移一般情况下可以实现除2的效果
**********************************************************************/






//不创建第三个变量，实现两个数的交换
//int main()
//{
//
//	int a = 10;
//	int b = 20;
//	printf("交换前：a = %d, b = %d\n", a, b);
//	
//	a = a ^ b;
//	b = a ^ b; //b = (a ^ b) ^ b --- b = a 
//	a = a ^ b; //a = a ^(a ^ b)   ---- a = b
//	
//	//虽然在131代码中a = a ^ b,a的值被改变为30
//	//但是，这利用的是替换法，131中的表达式只是一个打开132，133中a和b的钥匙
//	//在132，133中，a和b真正用来赋值的值还是最初定义的10和20
//
//	printf("交换后：a = %d, b = %d\n", a, b);
//	return 0;
//}


//编写代码实现，求一个整数存储在内存中的二进制中1的个数

//int main()
//{
//	int n = 0;
//	int count = 0;
//
//	scanf("%d", &n);
//
//	while (n)
//	{
//		if (n % 2 == 1)
//			count++;
//		n /= 2;
//	}
//	
//	printf("%d\n", count);
//	
//	return 0;
//}
/*这个代码，当n为负数的时候，会出现问题*/

//调整
//定义n的时候，用unsigned int定义即可，当n = -1的时候，不会
//认为最前面是符号位，只是会将n作为一个很大的数去处理
//int main()
//{
//	unsigned int n = 0;
//	int count = 0;
//
//	scanf("%d", &n);
//
//	while (n)
//	{
//		if (n % 2 == 1)
//			count++;
//		n /= 2;
//	}
//
//	printf("%d\n", count);
//
//	return 0;
//}


//新的思路
//int main()
//{
//	int n = 0;
//	int count = 0;
//	scanf("%d", &n);
//
//	for (int i = 0; i < 32; i++)
//	{
//		if ((n >> i) & 1 == 1)
//		{
//			count++;
//		}
//	}
//	printf("%d\n", count);
//	return 0;
//}


//新的思路+新的算法

// n = n & (n-1) 
//该算法可以将n的2进制数的最右边的1去掉
//算法的力量！！！！！！！！！！！！！

//int main()
//{
//	int n = 0;
//	int count = 0;
//	scanf("%d", &n);
//
//	while (n)
//	{
//		n = n & (n - 1);
//		count++;
//	}
//
//	printf("%d\n", count);
//	return 0;
//}

//判断一个数是不是2的次方
//int main()
//{
//	int n = 0;
//	int count = 0;
//	scanf("%d", &n);
//	/*while (n)
//	{
//		n = n & (n - 1);
//		count++;
//	}
//	printf("%d\n", count);*/
//	if ((n & (n - 1)) == 0)
//	{
//		printf("Yes\n");
//	}
//	else
//	{
//		printf("No\n");
//	}
//	return 0;
//}

//写代码x的二进制序列的第y位修改为1，然后再改回0

//int main()
//{
//	int x = 0;
//	scanf("%d", &x);
//	int y = 0;
//	scanf("%d", &y);
//	
//	x = x | (1 << y - 1); //x等于x或上1向左移动y-1位
//	
//	printf("%d\n", x);
//
//	x = x & ~(1 << y - 1);
//	printf("%d\n", x);
//	return 0;
//}